using System;
using System.Collections.Generic;

namespace QuickFiniteStateMachine
{
    public class QuickFSM<T>
    {
        private Dictionary<T, QuickState<T>> _states;
        private QuickState<T> _currentState;

        public QuickFSM() { _states = new Dictionary<T, QuickState<T>>(); }

        public void UpdateStates(T key, QuickState<T> state) { _states.Add(key, state); }

        public void Update() { _currentState.Update(); }

        public void Switch(T stateKey)
        {
            _currentState.Exit();
            _currentState = _states[stateKey];
            _currentState.Enter();
        }

        public void FSMStart(T stateKey)
        {
            _currentState = _states[stateKey];
            _currentState.Enter();
        }
    }

    public class QuickState<T>
    {
        private Action ON_Enter = delegate { };
        private Action ON_Update = delegate { };
        private Action ON_Exit = delegate { };

        /// <summary>
        /// Generate a state, and it will be add to the state list of the FSM. Update then check and switch.
        /// </summary>
        /// <param name="key">The name to find this state.</param>
        /// <param name="quickFSM">FSM using this state.</param>
        /// <param name="EUE_Events">Function Enter, Update and Exit. It doesn't matter if it's null.</param>
        /// <param name="conditions">The conditions to switch state.</param>
        /// <param name="results">Switch to which state.</param>
        public QuickState(T key, QuickFSM<T> quickFSM, Action[] EUE_Events, Func<bool>[] conditions, T[] results)
        {
            quickFSM.UpdateStates(key, this);

            if (EUE_Events != null)
            {
                ON_Enter += EUE_Events[0];
                ON_Update += EUE_Events[1];
                ON_Exit += EUE_Events[2];
            }

            for (int i = 0; i < conditions.Length; i++)
            {
                Func<bool> condition = conditions[i];//unboxing, otherwise the value will no longer exist so that the function can not get it
                T result = results[i];
                ON_Update += delegate { if (condition()) { quickFSM.Switch(result); }; };
            }
        }

        public void Enter() { ON_Enter(); }
        public void Update() { ON_Update(); }
        public void Exit() { ON_Exit(); }
    }
}
